(defun position-categories (var)
    (mapcar #' (lambda (rd) (which (mapcar #'(lambda (ch) (equal rd ch)) var)))
          (remove-duplicates var  :test 'equal)))

(defmeth boxplot-proto :isnew 
  (data &key title variable-labels point-labels enable-equate jitter
        boxes diamonds mean-line median-line enable-connect-points
        y-axis-label location size go-away show legend1 legend2
        dot-plot-only (original-order nil))
  (when original-order
        (send self :add-slot 'original-order);PV 
        (send self :slot-value 'original-order original-order));PV used for re-sorting the data
  (send self :data 
        (cond ((matrixp data) (column-list data))
          ((or (not (listp data)) (numberp (car data))) (list data))
          (t data)))
  (send self :num-obs (length (first (send self :data))))
  (send self :num-var (length (send self :data)))
  (send self :show-variable-labels nil)
  (let ((initial (send self :show-variable-labels)))
    (send self :show-variable-labels nil)
    (call-next-method 2 :title title :variable-labels variable-labels
                      :location location :size size :go-away go-away :show nil)
    (send self :show-variable-labels initial))
  (let* ((n nil)
         (x nil)
         (loc nil)
         (box-redraw 
          (send graph-item-proto :new "Redraw Plot" self :refresh-screen))
         )
    (send self :legend1 legend1)
    (send self :legend2 legend2)
    (send self :x-axis nil )
    (send self :make-two-plot-menus 
        "BoxPlot"
        :hotspot-items '(help dash link dash
                               print save copy)
        :popup-items '(showing-labels mouse resize-brush dash
                       erase-selection focus-on-selection view-selection dash 
                       select-all show-all dash
                       symbol color))
    (send self :button-overlay
          (send self :plot-buttons :margin (list
                                            0 (+ 17 (send self :text-descent)) 
                                            0 (+ 17 (send self :text-descent)))
                :new-x nil :new-y nil :mouse-mode t :equate enable-equate))
    (unless dot-plot-only 
            (send self :add-overlay (send boxplot-overlay-proto :new)))
    (send self :boxes boxes)
    (send self :diamonds diamonds)
    (send self :median-line median-line)
    (send self :mean-line mean-line)
    (send self :jitter jitter)
    (send self :connect-points nil)
    (send self :enable-equate enable-equate)
    (send self :equate enable-equate)
    (send self :enable-connect-points enable-connect-points)
    (send self :retain-point-states enable-connect-points)
    (when *color-mode* (send self :use-color t))
    (send self :brush 0 0 20 10)
    (send self :y-axis-label y-axis-label)
    (when (not point-labels) 
          (setf point-labels
                (mapcar #'(lambda (i) (format nil "~d" i))
                        (iseq (send self :num-obs)))))
    (when enable-equate (send self :normed-data (send self :normalize data)))
    (send self :new-plot (send self :data) 
          :title title
          :variable-labels variable-labels
          :point-labels point-labels)
    (send self :show-variable-labels t)
    (send self :showing-labels nil)
    (apply #'send self :margin (+ (send self :margin) (list 0 0 10 0)))
    (when show (send self :show-window))
    self))

(defmeth boxplot-proto :new-plot 
  (data &key title variable-labels point-labels) 
  (let ((n nil)
        (x nil)
        (loc nil)
        (nvar nil)
        (normed-data nil)
        (jitter 0)
        (color? (and (send (send self :button-overlay) :color-mode) 
                     (> *color-mode* 0)))
        (old-colors nil)
        (old-symbols nil)
        (old-states nil)
        (retain-pt-states (send self :retain-point-states))
        (y-name (send self :y-axis-label)))
    
   (send self :start-buffering)

    (setq data (cond 
                 ((matrixp data) (column-list data))
                 ((or (not (listp data)) (numberp (car data))) (list data))
                 (t data)))
    (send self :data data)
    (setf nobs (length (first data)))
    (setf nvar (length data))
    (when (or (/= nobs (send self :num-obs))
              (/= nvar (send self :num-var)))
          (setf retain-pt-states nil)
          (send self :num-obs nobs)
          (send self :num-var nvar))
    (when (send self :enable-equate)
          (send self :normed-data (send self :normalize data))
          (if (send self :equate)
              (setf data (send self :normed-data))
              (setf data (send self :data))))
    (when (and retain-pt-states (> (send self :num-points) 0)) 
          (setf old-colors 
                (send self :point-color (iseq nobs)))
          (setf old-symbols
                (send self :point-symbol (iseq nobs)))
          (setf old-states
                (send self :point-state (iseq nobs)))
        )
    (send self :clear) 
    (setf n (mapcar #'length data))
    (setf x (* (mean n) (iseq (length n))))
    (send self :x x)
    (when (not variable-labels) 
          (setf variable-labels (repeat "" (length data))))
    (send self :variable-labels variable-labels)
    (let ((range (get-nice-range (min data) (max data) 4)))
      (send self :range 1 (nth 0 range) (nth 1 range))
      (send self :y-axis t t (nth 2 range)))
    (send self :range 0 (- (first x) (/ (first n) 2))
          (+ (last  x) (/ (last  n) 2)))
    (when (not (send self :has-slot 'original-order))
          (dotimes (i nvar)
             (when (send self :jitter)
                   (setf jitter 
                         (* (- (uniform-rand (length (nth i data))) .55) .025
                            (abs (apply (function -) (send self :range 0))))))
             (send self :add-points 
                   (+ jitter (repeat (nth i x) (length (nth i data))))
                   (nth i data))))
  
    (when (send self :has-slot 'original-order) ;this applies to catbox
          
          (setf varx
                (combine (mapcar #'(lambda (i d) 
                                     (+ 
                                      (* (- (uniform-rand (length d)) .55) .025
                                         (abs (apply (function -) (send self :range 0))))
                                      (repeat (nth i x) (length d))))
                                       (iseq nvar) data)))
          (setf vary (combine data))
          (setf order (send self :slot-value 'original-order))
          (setf (select varx order) (select varx (iseq (length varx))))
          (setf (select vary order) (select vary (iseq (length vary))))
          
         (send self :add-points  
               varx vary
          ))
    
    (send self :point-color (iseq (send self :num-points))
          (if color?
              (if (not old-colors)
                  'blue
                  (repeat old-colors nvar))
              nil))
    (send self :point-symbol (iseq (send self :num-points))
          (if (not old-symbols)
                  'disk
                  (repeat old-symbols nvar)))
    
    ;(when point-labels (send self :showing-labels t))
    (when (not point-labels) 
          (setf point-labels
                (mapcar #'(lambda (i) (format nil "~d" i))
                        (iseq (send self :num-obs)))))
    (when (and (send self :enable-connect-points) 
               (/= (length (combine data)) (length point-labels)))
          (setf point-labels 
                (combine point-labels 
                         (repeat " " (- (length (combine data))
                                        (length point-labels))))))
    (send self :point-label (iseq (length point-labels)) point-labels)
    (send self :variable-label 1 
          (if (send self :equate) 
              (strcat "Normalized " y-name) y-name))
    
    (send self :point-state (iseq (send self :num-points))
          (if (not old-states)
                  'normal
                  (repeat old-states nvar)))
    
    (when (and retain-pt-states (> nvar 1))
          (let* ((ptst (send self :point-state (iseq nobs)))
                 (ptsel 
                  (which (mapcar #'(lambda (i) 
                           (equal 'selected (select ptst i))) 
                                 (iseq nobs)))))
            (when ptsel 
                  (send self :parallel ptsel 'selected nobs nvar))))
    (send self :change-plot)
    (send self :buffer-to-screen))
  )



(defmeth boxplot-proto :adjust-points (pts s &optional mouse-mode)
  (let* ((enabled (send self :enable-connect-points))
         (num-obs (if enabled
                      (send self :num-obs)
                      (length (combine (send self :data)))))
         (num-var (send self :num-var))
         )
;(format t "BP: Adjust Points: ~d~%" (list pts s))
    (when (not mouse-mode) (setf mouse-mode (send self :mouse-mode)))
    (cond 
      ((eq s 'selected) 
       (send self :propagate-selection 
             pts 'selected num-obs num-var mouse-mode)
       )
    ((eq s 'hilited)
     (let* ((point-states (send self :point-state (iseq num-obs)))
            (hilited-pts (which (map-elements #'eq 'hilited point-states)))
            (low-pts (if enabled (when pts (mod pts num-obs)) pts)))
       (when pts
             (send self :propagate-selection 
                   (set-difference hilited-pts low-pts) 'normal 
                   num-obs num-var mouse-mode)
             (send self :propagate-selection 
                   (set-difference low-pts hilited-pts) 'hilited
                    num-obs num-var mouse-mode)
             )
       (when (and hilited-pts (not pts))
             (send self :propagate-selection hilited-pts 'normal
                    num-obs num-var mouse-mode)
             (send self :change-plot))))))
  (when (send self :links)
  (mapcar #'(lambda (plot) (send plot :adjust-screen)) (remove self (send self :links))));PV this guarantees that other plots receive the adjust screen message and the regression lines feature will work
)
  
    